#!/usr/bin/env python

import os

from gppylib.commands.base import ExecutionError
from gppylib.operations.test.regress.test_package import GppkgTestCase, skipIfNoStandby, unittest, GppkgSpec, RPMSpec, ARCHIVE_PATH, RPM_DATABASE, run_command

class SharedDependenciesTestCase(GppkgTestCase):
    """Covers install/update/remove of gppkgs which have a shared dependency"""
    def setUp(self):
        self.cleanup()

        self.alpha_spec = GppkgSpec("alpha", "1.0")
        self.A_spec = RPMSpec("A", "1", "1", ["B = 1-1", "shared >= 1-1"])
        self.B_spec = RPMSpec("B", "1", "1") 

        self.beta_spec = GppkgSpec("beta", "1.0")
        self.C_spec = RPMSpec("C", "1", "1", ["D = 1-1", "shared >= 1-1"])
        self.D_spec = RPMSpec("D", "1", "1")

        self.shared_dep_spec = RPMSpec("shared", "1", "1") 

    def tearDown(self):
        self.cleanup()
        results = run_command('rpm -qa --dbpath %s' % RPM_DATABASE)
        rpms = results.split()
        for rpm in rpms:
            run_command('rpm -e %s --dbpath %s' % (rpm, RPM_DATABASE))
 
    def test00_build(self):
        self.build(self.alpha_spec, self.A_spec, [self.B_spec, self.shared_dep_spec])
        self.build(self.beta_spec, self.C_spec, [self.D_spec, self.shared_dep_spec])

    def test01_install(self):
        self.install(self.alpha_spec.get_filename())
        self.install(self.beta_spec.get_filename())
    
    def test02_uninstall(self):
        self.install(self.alpha_spec.get_filename())
        self.install(self.beta_spec.get_filename())
    
        self.remove(self.beta_spec.get_filename())
    
        self.check_rpm_install(self.shared_dep_spec.get_package_name())

    def test03_update(self):
        """
        Covers the case of update of gppkg with a shared dependency
        """
        self.install(self.alpha_spec.get_filename())
        self.install(self.beta_spec.get_filename()) 

        #package to be updated
        update_spec = GppkgSpec("alpha", "1.1")
        rpm_spec = RPMSpec("A", "1", "2", ["B = 1-1", "shared >= 2-1"])
        dep_spec = self.B_spec
        shared_dep_spec = RPMSpec("shared", "2", "1")
        self.build(update_spec, rpm_spec, [dep_spec, shared_dep_spec])
        
        self.update(update_spec.get_filename())

        self.check_rpm_uninstall(self.shared_dep_spec.get_package_name())
        self.check_rpm_install(shared_dep_spec.get_package_name())

    def test04_install_dependencies_incompatible(self):
        """
        Install gppkg alpha with dependencies B, shared
        Install gppkg gamma with dependencies F, shared 
        where version(gamma.shared) < version(alpha.shared)
        """
        shared_dep_spec = RPMSpec("shared", "0", "1")
        F_spec = RPMSpec("F", "1", "1")
        E_spec = RPMSpec("E", "1", "1", ["F = 1-1", "shared = 0-1"])
        gamma_spec = GppkgSpec("gamma", "1.0")
        self.build(gamma_spec, E_spec, [F_spec, shared_dep_spec]) 

        self.install(self.alpha_spec.get_filename())

        #The error generated by gppkg when we try to install a package with a lower version
        #when a higher version is already installed will be of the form
        #gppkg:fips1:subraa4-[INFO]:-Starting gppkg with args: --install test-1.0-Linux-x86_64.gppkg
        #gppkg:fips1:subraa4-[INFO]:-Installing package test-1.0-Linux-x86_64.gppkg
        #gppkg:fips1:subraa4-[INFO]:-Validating rpm installation cmdStr='rpm --test -i /data/abhijits/greenplum/.tmp/dep-1-1.x86_64.rpm /data/abhijits/greenplum/.tmp/shared-1-1.x86_64.rpm /data/abhijits/greenplum/.tmp/test-1-1.x86_64.rpm --dbpath /data/abhijits/greenplum/share/packages/database --prefix /data/abhijits/greenplum'
        #gppkg:fips1:subraa4-[INFO]:-Exception = 'shared-2-1.x86_64.rpm'
        #gppkg:fips1:subraa4-[INFO]:-Exception = 'shared-2-1.x86_64.rpm'
        #gppkg:fips1:subraa4-[CRITICAL]:-gppkg failed. (Reason=''shared-2-1.x86_64.rpm'') exiting...

        #rpm --test command blows up and that is the main reason for the error.
        #rpm --test -i shared-2-1.x86_64.rpm gives the following error when a newer version is already installed,
        #   package shared-1-1.x86_64 is already installed
        with self.assertRaises(ExecutionError):
            self.install(gamma_spec.get_filename())

        self.check_rpm_uninstall(shared_dep_spec.get_package_name())
        
        self.check_rpm_install(self.shared_dep_spec.get_package_name())

    def test05_update_dependencies_incompatible(self):
        """
        Installs gppkg alpha with dependencies B, shared
        Update gppkg alpha' with dependencies B, shared
        where version(alpha'.shared) < version(alpha.shared) and version(alpha') > version(alpha)
        """
        update_gppkg_spec = GppkgSpec("alpha", "2.0")
        B_spec = self.B_spec
        A_spec = RPMSpec("A", "1", "1", ["B = 1-1", "shared = 0-1"])
        shared_dep_spec = RPMSpec("shared", "0", "1")
        self.build(update_gppkg_spec, A_spec, [B_spec, shared_dep_spec])

        self.install(self.alpha_spec.get_filename())
       
        with self.assertRaises(ExecutionError): 
            self.update(update_gppkg_spec.get_filename()) 

    def test06_MPP_15788(self):
        """
        This test covers the case where we want to update a package
        but are unable to do so due to the restrictions imposed by 
        another version of the dependency already installed on the system.
        """

        A_spec = RPMSpec("A", "1", "1", ["B = 1-1", "shared = 1-1"])
        C_spec = RPMSpec("C", "1", "1", ["D = 1-1", "shared = 1-1"])
        
        self.build(self.alpha_spec, A_spec, [self.B_spec, self.shared_dep_spec])
        self.build(self.beta_spec, C_spec, [self.D_spec, self.shared_dep_spec])
        
        self.install(self.alpha_spec.get_filename()) 
        self.install(self.beta_spec.get_filename()) 

        #package to be updated
        update_gppkg_spec = GppkgSpec("alpha", "1.1")
        A_spec = RPMSpec("A", "2", "1", ["B = 2-1", "shared = 2-1"])
        B_spec = RPMSpec("B", "2", "1")
        shared_dep_spec = RPMSpec("shared", "2", "1")
        self.build(update_gppkg_spec, A_spec, [B_spec, shared_dep_spec]) 
       
        with self.assertRaises(ExecutionError): 
            self.update(update_gppkg_spec.get_filename())

    @unittest.expectedFailure
    def test07_MPP_15789(self):
        """
        This test covers the case of obsolete dependencies.
        When we update a gppkg and the new gppkg has different
        dependencies from the original gppkg, the dependencies 
        of the original gppkg will get left behind. When we 
        remove the gppkg, only the newer dependencies will be removed
        and the old ones will still remain on the system. 
        """

        update_gppkg_spec = GppkgSpec("alpha", "1.1")
        A_spec = RPMSpec("A", "2", "1", ["B = 1-1"])
        B_spec = self.B_spec
        
        self.build(update_gppkg_spec, A_spec, [B_spec])
        
        self.install(self.alpha_spec.get_filename())
       
        self.update(update_gppkg_spec.get_filename())

        self.remove(update_gppkg_spec.get_filename()) 

        results = run_command("rpm -qa --dbpath %s" % RPM_DATABASE)

        self.assertEqual(results, "")

if __name__ == "__main__":
    unittest.main()
